home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / MIDIMOD2.ZIP / TEXTWIN.C < prev    next >
Text File  |  1993-06-26  |  14KB  |  603 lines

  1. /*
  2.  * TEXTWIN.C - Text-windowing system
  3.  * (c)opyright Andrew Scott 1993
  4.  *
  5.  * Turbo C 2.0
  6.  *
  7.  * Description: Provides a simple text-menuing interface. Includes pop-down
  8.  *              menus, and scrolling windows. To use, set up a main window
  9.  *              with the MainWindow() function.
  10.  *   eg. MainWindow("Title", 2, "Files", 'f', "Help", 'h');
  11.  *
  12.  *              Then set the commands and command-numbers for each menu use
  13.  *              the SetMenu function.
  14.  *   eg. SetMenu(0, 3, "Open",'o',0, "Close",'c',1, "Quit",'q',2);
  15.  *       SetMenu(1, 3, "Help",'h',3, "------------",-1,-1, "About",'a',4);
  16.  *
  17.  *              Now just make a call to Choice() and the number it returns
  18.  *              will be the command-number of the choice
  19.  *   eg. If Help|About is chosen, 4 will be returned.
  20.  *
  21.  *              If you want to get the user to select an option from a list
  22.  *              of options, make an array of strings with the option
  23.  *              descriptions in them (ensure final element is NULL). The
  24.  *              element number chosen will be returned (first element = 0)
  25.  *              after a call to ScrollChoice()
  26.  *   eg. If the array is a, and the maximum string length is l, make the call
  27.  *       ScrollChoice("BetterTitle", a, l);
  28.  *
  29.  *              To display test inside a box, call DrawBox() with a NULL-
  30.  *              terminated array of strings.
  31.  *   eg. If the array is a, call
  32.  *       DrawBox(a);
  33.  *
  34.  *              To display text inside a box, and then wait for a key to be
  35.  *              pressed, set up a NULL-terminated array of strings and call
  36.  *              the InfoBox() function
  37.  *   eg. If the array is a, make the call
  38.  *       InfoBox(a);
  39.  *
  40.  *              If you want to get input as well as print a box, make a call
  41.  *              to DialogBox(), if nothing is entered, a default string is
  42.  *              returned
  43.  *   eg. DialogBox(a, "C:\") would return "C:\" if nothing was entered.
  44.  *
  45.  *
  46.  * Author: Andrew Scott (Adrenalin Software)
  47.  *
  48.  * Date: 14/3/1993 ver 0.1
  49.  *       17/4/1993 ver 0.1a
  50.  */
  51.  
  52. #include <conio.h>
  53. #include <stdlib.h>
  54. #include <stdio.h>
  55. #include <stdarg.h>
  56. #include <string.h>
  57. #include <ctype.h>
  58.  
  59. /* Maximum number of chars in a menu title */
  60. #define MAXMENUWIDTH 9
  61. /* Maximum number of chars in a menu command */
  62. #define MAXCOMMWIDTH 12
  63. /* Border graphics */
  64. #define CRNRTL '┌'
  65. #define CRNRTR '┐'
  66. #define CRNRBL '└'
  67. #define CRNRBR '┘'
  68. #define HORIBAR '─'
  69. #define VERTBAR '│'
  70.  
  71. typedef char *string;
  72.  
  73. struct MenuStruct {
  74.     char n[MAXCOMMWIDTH+1]; /* Item name ("" = no items) */
  75.     int k;                  /* Key-press selector (lower case) */
  76.     int x;                  /* Function reference number (-ve = no command) */
  77. };
  78. typedef struct MenuStruct *MenuItem;
  79.  
  80. struct MenuBar {
  81.     char n[MAXMENUWIDTH+1]; /* Menu name ("" = no menus) */
  82.     int k;                  /* Key-press selector (lower case) */
  83.     MenuItem m;             /* Menu items */
  84. } *MainW;
  85.  
  86. void MainWindow(string title, int num, ...)
  87. /* Post: Screen is set up with a nice title and num menus */
  88. {
  89.     va_list args;
  90.     string t;
  91.     int i;
  92.     struct MenuBar *c;
  93.  
  94.     c = MainW = (struct MenuBar *) malloc(sizeof(struct MenuBar) * (num + 1));
  95.     va_start(args, num);
  96.     textmode(C80);
  97.     textcolor(CYAN);
  98.     textbackground(BLACK);
  99.     clrscr();
  100.     textbackground(BLUE);
  101.     textcolor(WHITE);
  102.     i = 80 - strlen(title);
  103.     cprintf("%*c%s%*c", i/2, ' ', title, i/2 + i%2, ' ');
  104.     textcolor(YELLOW);
  105.     cprintf(" ");
  106.     for (i = num; i--; c++) {
  107.         t = (va_arg(args, string));
  108.         strcpy(c->n, t);
  109.         cprintf("%-*s", MAXMENUWIDTH, t);
  110.         c->k = (va_arg(args, int));
  111.         c->m = NULL;
  112.     }
  113.     c->n[0] = 0;
  114.     cprintf("%*c", 79 - MAXMENUWIDTH * num, ' ');
  115.     va_end(args);
  116. }
  117.  
  118. void EndWindows()
  119. /* Post: Windows are freed up */
  120. {
  121.     struct MenuBar *c;
  122.     MenuItem t;
  123.  
  124.     for (c = MainW; c->n[0]; c++)
  125.         free(c->m);
  126.     free(MainW);
  127. }
  128.  
  129. void SetMenu(int menu, int n, ...)
  130. /* Post: n commands has been set in menu #menu (0 = 1st) */
  131. {
  132.     va_list args;
  133.     string t;
  134.     struct MenuBar *c1;
  135.     MenuItem c2;
  136.  
  137.     int i;
  138.  
  139.     for (i = menu, c1 = MainW; i-- && c1->n[0]; c1++);
  140.     if (! c1->n[0])
  141.         return; /* error */
  142.     c1->m = c2 = (MenuItem) malloc(sizeof(struct MenuStruct) * (n + 1));
  143.     va_start(args, n);
  144.     for (; n--; c2++) {
  145.         t = va_arg(args, string);
  146.         strcpy(c2->n, t);
  147.         c2->k = va_arg(args, int);
  148.         c2->x = va_arg(args, int);
  149.     }
  150.     c2->n[0] = 0;
  151. }
  152.  
  153. int _Menulength_; /* ignore this unstructured global variable ;) */
  154.  
  155. void PrintMenu(MenuItem m, int x)
  156. /* Post: The menu which is pointed to by m is printed at column x */
  157. {
  158.     int i;
  159.     char t[MAXCOMMWIDTH + 3];
  160.  
  161.     i = MAXCOMMWIDTH+2;
  162.     t[i] = 0;
  163.     while (i--)
  164.         t[i] = HORIBAR;
  165.     textcolor(YELLOW);
  166.     textbackground(BLUE);
  167.     gotoxy(x, 3);
  168.     cprintf("%c%s%c", CRNRTL, t, CRNRTR);
  169.     _Menulength_ = 2;
  170.     i = 4;
  171.     while (m->n[0]) {
  172.         _Menulength_++;
  173.         gotoxy(x, i++);
  174.         cprintf("%c %-*s %c", VERTBAR, MAXCOMMWIDTH, (m++)->n, VERTBAR);
  175.     }
  176.     gotoxy(x, i);
  177.     cprintf("%c%s%c", CRNRBL, t, CRNRBR);
  178. }
  179.  
  180. void ClearMenu(int x)
  181. /* Post: The last menu printed at column x is now gone */
  182. {
  183.     int i = 3;
  184.  
  185.     textcolor(CYAN);
  186.     textbackground(BLACK);
  187.     while (_Menulength_--) {
  188.         gotoxy(x, i++);
  189.         cprintf("%*c", MAXCOMMWIDTH + 4, ' ');
  190.     }
  191. }
  192.  
  193. void PrintComm(MenuItem m, int x, int y)
  194. /* Post: Item *m is highlighted at column x, position y */
  195. {
  196.     gotoxy(x+1, y+4);
  197.     textcolor(MAGENTA);
  198.     textbackground(BLACK);
  199.     cprintf(" %-*s ", MAXCOMMWIDTH, m->n);
  200. }
  201.  
  202. void ClearComm(MenuItem m, int x, int y)
  203. /* Post: Item *m is normalized at column x, position y */
  204. {
  205.     gotoxy(x+1, y+4);
  206.     textcolor(YELLOW);
  207.     textbackground(BLUE);
  208.     cprintf(" %-*s ", MAXCOMMWIDTH, m->n);
  209. }
  210.  
  211. void PrintBar(string s, int w, int y)
  212. /* Post: String s (width w) is highlighted in the text window on line y */
  213. {
  214.     gotoxy(1, y+1);
  215.     textcolor(WHITE);
  216.     textbackground(BLACK);
  217.     cprintf(" %-*s ", w, s);
  218. }
  219.  
  220. void ClearBar(string s, int w, int y)
  221. /* Post: String s (width w) is normalized in the text window on line y */
  222. {
  223.     gotoxy(1, y+1);
  224.     textcolor(BLACK);
  225.     textbackground(CYAN);
  226.     cprintf(" %-*s ", w, s);
  227. }
  228.  
  229. void Beep()
  230. /* Post: Speaker has made a beep */
  231. {
  232.     printf("%c", 7);
  233. }
  234.  
  235. int Choice()
  236. /*
  237.  * Returns: a function reference number corresponding to a chosen command,
  238.  *   but returns -1 on an error.
  239.  */
  240. {
  241.     int ch;
  242.     struct MenuBar *c;
  243.     MenuItem p, q;
  244.     int i, fx = -1, y;
  245.  
  246.     textcolor(CYAN);
  247.     textbackground(BLACK);
  248.     gotoxy(1, 25);
  249.     do {
  250.         cprintf("\rPress the letter of the menu you wish to select.");
  251.         ch = tolower(getch());
  252.         for (c = MainW, i = 0; c->n[0] && c->k != ch; c++, i++);
  253.         i = 2 + MAXMENUWIDTH * i;
  254.         if (c->n[0] != 0)
  255.             do {
  256.                 cprintf("\rPress a letter, or use cursor keys and <RETURN> to select a command.");
  257.                 gotoxy(i, 2);
  258.                 textbackground(BLUE);
  259.                 textcolor(LIGHTRED);
  260.                 cprintf("%-*s", MAXMENUWIDTH, c->n);
  261.                 PrintMenu(p = c->m, i);
  262.                 PrintComm(p, i, y = 0);
  263.                 do {
  264.                     ch = tolower(getch());
  265.                     if (!ch) {
  266.                         ch = -getch();
  267.                         if (ch==-72) /* up-arrow */
  268.                             if (!y)
  269.                                 Beep();
  270.                             else {
  271.                                 ClearComm(p--, i, y--);
  272.                                 PrintComm(p, i, y);
  273.                             }
  274.                         else if (ch==-80) /* down-arrow */
  275.                             if (! (p+1)->n[0])
  276.                                 Beep();
  277.                             else {
  278.                                 ClearComm(p++, i, y++);
  279.                                 PrintComm(p, i, y);
  280.                             }
  281.                     } else {
  282.                         for (q = c->m; q->n[0] && q->k != ch; q++);
  283.                         if (q->n[0])
  284.                             fx = q->x;
  285.                     }
  286.                 } while ((ch==-72 || ch==-80) && fx < 0);
  287.                 if (ch==13 && fx < 0)
  288.                     fx = p->x;
  289.                 ClearMenu(i);
  290.                 gotoxy(i, 2);
  291.                 textbackground(BLUE);
  292.                 textcolor(YELLOW);
  293.                 cprintf("%-*s", MAXMENUWIDTH, c->n);
  294.                 textcolor(CYAN);
  295.                 textbackground(BLACK);
  296.                 gotoxy(1, 25);
  297.                 clreol();
  298.                 if (ch==-75)
  299.                     if (i==2)
  300.                         Beep();
  301.                     else {
  302.                         i -= MAXMENUWIDTH;
  303.                         c--;
  304.                     }
  305.                 else if (ch==-77)
  306.                     if (! (c+1)->n[0])
  307.                         Beep();
  308.                     else {
  309.                         i += MAXMENUWIDTH;
  310.                         c++;
  311.                     }
  312.             } while (ch != 27 && fx < 0);
  313.         clreol();
  314.     } while (fx < 0);
  315.     return fx;
  316. }
  317.  
  318. void ClearWin()
  319. /* Post: Area below command and title bars is clear */
  320. {
  321.     textcolor(CYAN);
  322.     textbackground(BLACK);
  323.     window(1, 3, 80, 25);
  324.     clrscr();
  325.     window(1, 1, 80, 25);
  326. }
  327.  
  328. int ScrollChoice(string title, string *sp, int w)
  329. /*
  330.  * Returns: The offset of the string from s which is chosen, -1 on none
  331.  *    s points to the start of a list of strings, max length w, NULL term.
  332.  */
  333. {
  334.     string s, t, *srt, *end;
  335.     int l, p, cur, ch, x = -1;
  336.  
  337.     if (*sp==NULL) /* have to have at least 1 thing to print */
  338.         return -1;
  339.     if (strlen(title) > w)
  340.         w = strlen(title);
  341.     textcolor(CYAN);
  342.     textbackground(BLACK);
  343.     gotoxy(1, 25);
  344.     cprintf("Use cursor keys and <RETURN> to make a selection.");
  345.     s = t = (string) malloc(w + 3);
  346.     for (p = w+2; p--; *(t++) = HORIBAR);
  347.     *t = 0;
  348.     gotoxy(5,3);
  349.     textcolor(BLACK);
  350.     textbackground(CYAN);
  351.     cprintf("%c%s%c", CRNRTL, s, CRNRTR);
  352.     gotoxy(6 + (w - strlen(title))/2, 3);
  353.     cprintf(" %s ", title);
  354.     srt = end = sp;
  355.     for (end = sp, l = 0; *end!=NULL && l<20; l++, end++) {
  356.         gotoxy(5, l+4);
  357.         cprintf("%c %-*s %c", VERTBAR, w, *end, VERTBAR);
  358.     }
  359.     gotoxy(5, l+4);
  360.     cprintf("%c%s%c", CRNRBL, s, CRNRBR);
  361.     free(s);
  362.     window(6, 4, 8+w, l+3);
  363.     PrintBar(*srt, w, p = 0);
  364.     cur = 0;
  365.     x = -1;
  366.     do {
  367.         ch = tolower(getch());
  368.         if (!ch) {
  369.             ch = -getch();
  370.             if (ch==-72)
  371.                 if (!cur)
  372.                     Beep();
  373.                 else if (p) {
  374.                     ClearBar(*(srt+p), w, p);
  375.                     p--;
  376.                     PrintBar(*(srt+p), w, p);
  377.                     cur--;
  378.                 } else {
  379.                     ClearBar(*(srt--), w, 0);
  380.                     gotoxy(1, 1);
  381.                     insline();
  382.                     gotoxy(w+3, 1);
  383.                     cprintf("%c", VERTBAR);
  384.                     PrintBar(*srt, w, 0);
  385.                     end--;
  386.                     cur--;
  387.                 }
  388.             else if (ch==-80)
  389.                 if (p==l-1 && *end==NULL)
  390.                     Beep();
  391.                 else if (p < l-1) {
  392.                     ClearBar(*(srt+p), w, p);
  393.                     p++;
  394.                     cur++;
  395.                     PrintBar(*(srt+p), w, p);
  396.                 } else {
  397.                     ClearBar(*(end-1), w, p);
  398.                     gotoxy(w+3, l);
  399.                     cprintf("%c", VERTBAR);  /* argh.. cant print at final corner */
  400.                     cur++;
  401.                     PrintBar(*end, w, p);
  402.                     end++;
  403.                     srt++;
  404.                 }
  405.         } else if (ch==13)
  406.             x = cur;
  407.     } while (x < 0 && ch != 27);
  408.     ClearWin();
  409.     return x;
  410. }
  411.  
  412. void PrintBox(string *sp, int *x1, int *y1, int *w1)
  413. /*
  414.  * Post: The NULL-terminated array of strings pointed to by sp is printed,
  415.  *    and x1, y1 are set to be the co-ordinates of the bottom-left corner,
  416.  *    w1 is set to be the width of the inside of the box.
  417.  */
  418. {
  419.     int w, x, i, j;
  420.     string s, t, *c;
  421.  
  422.     if (*sp==NULL)
  423.         return;
  424.     c = sp;
  425.     for (w = strlen(*(c++)), i = 1; *c!=NULL; c++, i++)
  426.         if (w < (x = strlen(*c)))
  427.             w = x;
  428.     *w1 = w + 2;
  429.     *x1 = 1 + (x = (76 - w)/2);
  430.     i = 3 + (21 - i)/2;
  431.     s = t = (string) malloc(w+3);
  432.     for (j = w+2; j--; *(t++) = HORIBAR);
  433.     *t = 0;
  434.     textcolor(BLACK);
  435.     textbackground(CYAN);
  436.     gotoxy(x, i++);
  437.     cprintf("%c%s%c", CRNRTL, s, CRNRTR);
  438.     for (c = sp; *c!=NULL; c++) {
  439.         gotoxy(x, i++);
  440.         cprintf("%c %-*s %c", VERTBAR, w, *c, VERTBAR);
  441.     }
  442.     *y1 = i-1;
  443.     gotoxy(x, i);
  444.     cprintf("%c%s%c", CRNRBL, s, CRNRBR);
  445.     free(s);
  446. }
  447.  
  448. void DrawBox(string *sp)
  449. /* Post: The NULL-terminated array of strings pointed to by sp is printed */
  450. {
  451.     int i;
  452.  
  453.     PrintBox(sp, &i, &i, &i);
  454. }
  455.  
  456. char InfoBox(string *sp)
  457. /*
  458.  * Returns: The key pressed after the NULL-terminated array of strings
  459.  *    pointed to by sp is printed.
  460.  */
  461. {
  462.     int k;
  463.  
  464.     DrawBox(sp);
  465.     textcolor(CYAN);
  466.     textbackground(BLACK);
  467.     gotoxy(1, 25);
  468.     cprintf("Please press a key.");
  469.     k = getch();
  470.     ClearWin();
  471.     return k;
  472. }
  473.  
  474. string DialogBox(string *sp, string def)
  475. /* Pre: def != NULL */
  476. /*
  477.  * Returns: The string entered (or def if none entered), after printing
  478.  *    box filled with NULL-terminated strings sp.
  479.  */
  480. {
  481.     int x, y, w, ch, i=0;
  482.     string s;
  483.  
  484.     PrintBox(sp, &x, &y, &w);
  485.     s = (string) malloc(w+1);
  486.     s[w] = 0;
  487.     strncpy(s, def, w);
  488.     textcolor(CYAN);
  489.     textbackground(BLACK);
  490.     gotoxy(1, 25);
  491.     cprintf("Enter text, and when you are finished, press <RETURN>.");
  492.     textcolor(WHITE);
  493.     gotoxy(x, y);
  494.     cprintf("%-*s", w, s);
  495.     window(x, y, x+w-1, y);
  496.     gotoxy(1, 1);
  497.     x = strlen(s);
  498.     do {
  499.         if (!(ch = getch()))
  500.             ch = -getch();
  501.         if (ch==8 || ch==127)
  502.             if (!i)
  503.                 Beep();
  504.             else {
  505.                 cprintf("\b");
  506.                 clreol();
  507.                 x = --i;
  508.             }
  509.         else if (ch==-75)
  510.             if (!i)
  511.                 Beep();
  512.             else {
  513.                 cprintf("\b");
  514.                 i--;
  515.             }
  516.         else if (ch==-77)
  517.             if (i==x)
  518.                 Beep();
  519.             else {
  520.                 cprintf("%c", s[i]);
  521.                 i++;
  522.             }
  523.         else if (ch!=13 && ch!=27)
  524.             if (i==w-1)
  525.                 Beep();
  526.             else {
  527.                 cprintf("%c", ch);
  528.                 if (i==x)
  529.                     x++;
  530.                 s[i++] = ch;
  531.             }
  532.     } while (ch!=13 && ch!=27);
  533.     s[x] = 0;
  534.     if (ch==27) {
  535.         free(s);
  536.         strcpy(s = (string) malloc(strlen(def)+1), def);
  537.     }
  538.     ClearWin();
  539.     return s;
  540. }
  541.  
  542. /*
  543.  * This main function is for testing the basics of these routines.
  544.  * Leave it commented out when creating object files.
  545.  *
  546. main()
  547. {
  548.     string scrolly[] = {
  549.         "First one",
  550.         "Second option",
  551.         "3rd",
  552.         "4th",
  553.         "Fifth",
  554.         "This could go on for AGES",
  555.         "Why not stop soon?",
  556.         "Ok",
  557.         "How about the next one",
  558.         "Done",
  559.         "Nope",
  560.         "Here's another few..",
  561.         "Un",
  562.         "Deux",
  563.         "Trois",
  564.         "Quatre",
  565.         "When should I stop?",
  566.         "Not yet obviously.",
  567.         "Cinq",
  568.         "Six",
  569.         "Sept",
  570.         "I think that's enough",
  571.         "Well maybe one more.",
  572.         NULL
  573.     };
  574.     string diagbox[] = {
  575.         "Please enter some gibberish",
  576.         "below at the prompt please.",
  577.         "It WONT check your spelling.",
  578.         "",
  579.         "",
  580.         NULL
  581.     };
  582.     string s;
  583.  
  584.     MainWindow("Big Huge Title", 3, "Ace", 'a', "Bee", 'b', "seaCide", 'c');
  585.     SetMenu(0, 3, "First", 'f', 1, "------------", -1, -1, "Second", 's', 2);
  586.     SetMenu(1, 1, "Spelling", 's', 3);
  587.     SetMenu(2, 2, "I'd like", 'i', 4, "To be beside", 't', 5);
  588.     while (1)
  589.         switch (Choice()) {
  590.             case 1:
  591.                 ScrollChoice("Window Name", scrolly, 25);
  592.                 break;
  593.             case 3:
  594.                 s = DialogBox(diagbox, "sample");
  595.                 free(s);
  596.                 break;
  597.             case 5:
  598.                 exit(0);
  599.         }
  600. }
  601.  * Ok.. this ends the commented out part
  602.  */
  603.